package com.educatioin.manage.wechat.service;

import com.alibaba.fastjson.JSON;
import com.educatioin.manage.constant.WeChatApiConstant;
import com.educatioin.manage.wechat.dto.AccessTokenDto;
import com.educatioin.manage.wechat.dto.JsApiTicketDto;
import com.google.common.cache.Cache;
import com.google.common.cache.CacheBuilder;
import org.apache.commons.codec.digest.DigestUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.io.IOException;
import java.security.MessageDigest;
import java.util.*;
import java.util.concurrent.TimeUnit;

/**
 * Created by zhangchen on 2018/3/12.
 */
@Service
public class WeChatApiService {

    @Autowired
    private RestTemplate restTemplate;
    private static Logger logger = LoggerFactory.getLogger(WeChatApiService.class);
    //token缓存2小时
    Cache<String, String> tokenCache = CacheBuilder.newBuilder().expireAfterWrite(1L, TimeUnit.HOURS)
            .build();

    //jsapiticket缓存2小时
    Cache<String, String> jsApiTicketCache = CacheBuilder.newBuilder().expireAfterWrite(1L, TimeUnit.HOURS)
            .build();

    /**
     * 获取AccessToken，缓存token，2小时
     * @return
     */
    public AccessTokenDto getAccessToken(){
        //TODO 换redis ?缓存中有从缓存中取，没有就调用微信获取AccessToken接口
        String accessTokenStr = tokenCache.getIfPresent(WeChatApiConstant.TOKEN_CACHE_KEY);
        if (accessTokenStr == null) {
            accessTokenStr = restTemplate.getForObject( "https://api.weixin.qq.com/cgi-bin/token?grant_type=client_credential&appid=" + WeChatApiConstant.APP_ID + "&secret=" + WeChatApiConstant.APP_SECRET, String.class);
            AccessTokenDto accessToken = JSON.parseObject(accessTokenStr, AccessTokenDto.class);
            if (null==accessToken.getErrcode()) {
                tokenCache.put(WeChatApiConstant.TOKEN_CACHE_KEY, accessTokenStr);
            }
            return accessToken;
        }
        AccessTokenDto accessToken = JSON.parseObject(accessTokenStr, AccessTokenDto.class);
        return accessToken;
    }

    /**
     * 获取
     * @return
     */
    public JsApiTicketDto getJsApiTicket(){
        //TODO 换redis ?缓存中有从缓存中取，没有就调用微信获取AccessToken接口
        String jsApiTicketStr = jsApiTicketCache.getIfPresent(WeChatApiConstant.JS_API_TICKET_CACHE_KEY);
        if (jsApiTicketStr == null) {
            jsApiTicketStr = restTemplate.getForObject( "https://api.weixin.qq.com/cgi-bin/ticket/getticket?access_token=" + getAccessToken().getAccessToken()+ "&type=jsapi", String.class);
            JsApiTicketDto jsApiTicket = JSON.parseObject(jsApiTicketStr, JsApiTicketDto.class);
            if (0==jsApiTicket.getErrcode()) {
                jsApiTicketCache.put(WeChatApiConstant.JS_API_TICKET_CACHE_KEY, jsApiTicketStr);
            }
            return jsApiTicket;
        }

        JsApiTicketDto jsApiTicket = JSON.parseObject(jsApiTicketStr, JsApiTicketDto.class);
        return jsApiTicket;
    }

    /**
     * 获取微信js sdk配置所需要的签名
     * @param url
     * @return
     * @throws IOException
     */
    public String createSignature(String url) throws IOException {
        String nonceStr = create_nonce_str();
        String timestamp = create_timestamp();

        String signature = "jsapi_ticket="+ getJsApiTicket().getTicket();
        signature += "&noncestr="+nonceStr;
        signature += "&timestamp="+timestamp;
        signature += "&url="+url;

        try {
            MessageDigest crypt = MessageDigest.getInstance("SHA-1");
            crypt.reset();
            crypt.update(signature.getBytes("UTF-8"));
            signature = byteToHex(crypt.digest());
        } catch (Exception e) {
            logger.error("Signature for SHA-1 is error:{}",e);
        }

        Map<String, String> map = new HashMap<String, String>();
        map.put("timestamp", timestamp);
        map.put("nonceStr", nonceStr);
        map.put("signature", signature);
        map.put("appid", WeChatApiConstant.APP_ID);
        return JSON.toJSONString(map, true);
    }

    /**
     * 微信支付签名算法sign
     * @param parameters
     * @return
     */
    public static String createSign(SortedMap<String,String> parameters){
        StringBuffer sb = new StringBuffer();
        Set es = parameters.entrySet();//所有参与传参的参数按照accsii排序（升序）
        Iterator it = es.iterator();
        while(it.hasNext()) {
            Map.Entry entry = (Map.Entry)it.next();
            String k = (String)entry.getKey();
            Object v = entry.getValue();
            if(null != v && !"".equals(v)
                    && !"sign".equals(k) && !"key".equals(k)) {
                sb.append(k + "=" + v + "&");
            }
        }

        sb.append("key=" + WeChatApiConstant.MCH_KEY);
        String sign = DigestUtils.md5Hex(sb.toString()).toUpperCase();
        return sign;
    }

    public static String byteToHex(final byte[] hash) {
        Formatter formatter = new Formatter();
        for (byte b : hash) {
            formatter.format("%02x", b);
        }
        String result = formatter.toString();
        formatter.close();
        return result;
    }

    public static String create_nonce_str() {
        return UUID.randomUUID().toString();
    }

    public static String create_timestamp() {
        return Long.toString(System.currentTimeMillis() / 1000);
    }
}
